package net.neptech.service.impl;

import net.neptech.dto.schedule.ScheduleDto;
import net.neptech.model.schedule.ScheShift;
import net.neptech.model.schedule.Schedule;
import net.neptech.repository.ScheShiftRepository;
import net.neptech.repository.ScheduleRepository;
import net.neptech.service.ScheduleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;
import jakarta.persistence.criteria.*;

/**
 * @Author HuangZhengmin
 * @desc
 * @Date 2025/8/15 11:24
 * @Version 1.0
 */
@Service
public class ScheduleServiceImpl implements ScheduleService {

  @Autowired
  private ScheduleRepository scheduleRepository;

  @Autowired
  private ScheShiftRepository scheShiftRepository;

  @Override
  public void addSchedule(Schedule schedule) {
    //设置创建时间
    if(schedule.getCreateTime() == null){
      schedule.setCreateTime(new Date());
    }
    scheduleRepository.save(schedule);
  }

  @Override
  @Transactional
  public void batchAddSchedule(ScheduleDto scheduleDto) {
    List<Schedule> schedules = scheduleDto.getSchedules();
    Date now = new Date();//获取当前时间
    //遍历设置创建时间和更新时间
    schedules.forEach(schedule -> {
      schedule.setCreateTime(now);
    });
    scheduleRepository.saveAll(schedules);
  }

  @Override
  @Transactional
  public void batchAddOrUpdateSchedule(ScheduleDto scheduleDto) {

    List<Schedule> saveSchedules = new ArrayList<>();
    //获取前端传的数据
    List<Schedule> schedules = scheduleDto.getSchedules();
    Date now = new Date();//当前时间

    for (Schedule schedule : schedules) {
      // 关键：通过 shiftId 查询已存在的 ScheShift（确保关联持久态对象）
      Long shiftId = schedule.getShiftId();
      if (shiftId != null) {
        ScheShift existingShift = scheShiftRepository.findById(shiftId)
                .orElseThrow(() -> new RuntimeException("班次不存在：shiftId=" + shiftId));
        // 关联已持久化的班次（替换前端传递的临时对象）
        schedule.setScheShift(existingShift);
//        deleteSchedule(schedule.getScheduleId());
      } else {
        // 若 shiftId 为空，根据业务抛异常或处理
        throw new IllegalArgumentException("班次ID（shiftId）不能为空");
      }
      //1.如果scheduleId存在，则是修改
      if(schedule.getScheduleId() != null){
        // 从数据库查询现有数据（避免覆盖未传的字段）
        Schedule existingSchedule = scheduleRepository.findById(schedule.getScheduleId())
                .orElseThrow(() -> new RuntimeException("排班ID不存在: " + schedule.getScheduleId()));
        // 只更新允许修改的字段（避免覆盖 createTime 等）
        existingSchedule.setStaffName(schedule.getStaffName());
        existingSchedule.setDutyDay(schedule.getDutyDay());
        existingSchedule.setShiftId(schedule.getShiftId());
        existingSchedule.setDeptId(schedule.getDeptId());
        existingSchedule.setStatus(schedule.getStatus());
        existingSchedule.setManagerName(schedule.getManagerName());
        existingSchedule.setUpdateTime(now); // 设置更新时间

        saveSchedules.add(existingSchedule);
      }else{
        //2.如果scheduleId不存在，则是新增
        schedule.setCreateTime(now);
        saveSchedules.add(schedule);
      }
    }
    // 批量保存（JPA 的 saveAll 会自动判断是 insert 还是 update）
    scheduleRepository.saveAll(saveSchedules);
  }

  @Override
  public void updateSchedule(Schedule schedule) {
    //先查询再修改
    //1.先查询现有实体
    Schedule existSchedule = scheduleRepository.findById(schedule.getScheduleId())
            .orElseThrow(() -> new RuntimeException("排班记录不存在"));
    //2.修改
    existSchedule.setStaffName(schedule.getStaffName());
    existSchedule.setDutyDay(schedule.getDutyDay());
    existSchedule.setShiftId(schedule.getShiftId());
    existSchedule.setDeptId(schedule.getDeptId());
    existSchedule.setStatus(schedule.getStatus());
    existSchedule.setManagerName(schedule.getManagerName());
    existSchedule.setUpdateTime(new Date());
    //3.保存
    scheduleRepository.save(schedule);
  }

  @Override
  public void deleteSchedule(Long id) {
    //先查询再删除
    //1.先查询现有实体
    Schedule existSchedule = scheduleRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("排班记录不存在"));
    //2.删除
    scheduleRepository.deleteById(id);
  }

  // 在 net.neptech.service.impl.ScheduleServiceImpl 中
  @Override
  public List<Schedule> findSchedulesByCondition(Schedule condition) {
    return scheduleRepository.findAll((root, query, cb) -> {

      // 关键修改：显式加载关联的班次信息（LEFT JOIN），避免懒加载导致的序列化问题
      root.fetch("scheShift", JoinType.LEFT); // 启用这行代码

      List<Predicate> predicates = new ArrayList<>();

      // 1. 按 staffName 模糊查询（如果传入）
      if (StringUtils.hasText(condition.getStaffName())) {
        predicates.add(cb.like(root.get("staffName"), "%" + condition.getStaffName() + "%"));
      }

      // 2. 按 dutyDay 查询（如果传入）
      if (condition.getDutyDay() != null) {
        predicates.add(cb.equal(root.get("dutyDay"), condition.getDutyDay()));
      }

      // 3. 按 shiftId 查询（如果传入）
      if (condition.getShiftId() != null) {
        predicates.add(cb.equal(root.get("shiftId"), condition.getShiftId()));
      }

      // 4. 按 deptId 查询（如果传入）
      if (condition.getDeptId() != null) {
        predicates.add(cb.equal(root.get("deptId"), condition.getDeptId()));
      }

      // 5. 按 status 查询（如果传入）
      if (condition.getStatus() != null) {
        predicates.add(cb.equal(root.get("status"), condition.getStatus()));
      }

      //7. 按staffId 查询（如果传入）
      if (condition.getStaffId() != null) {
        predicates.add(cb.equal(root.get("staffId"), condition.getStaffId()));
      }

      // 6. 关联查询 ScheShift 的 shiftName（先检查是否为 null）
      if (condition.getScheShift() != null
              && StringUtils.hasText(condition.getScheShift().getShiftName())) {
        Join<Schedule, ScheShift> shiftJoin = root.join("scheShift", JoinType.LEFT);
        predicates.add(cb.like(shiftJoin.get("shiftName"),
                "%" + condition.getScheShift().getShiftName() + "%"));
      }


      return cb.and(predicates.toArray(new Predicate[0]));
    });
  }
}
